package model.genetic.genes;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class ValidLineDnaStrategy implements DnaStrategy {
	
	private Random random;

	public ValidLineDnaStrategy() {
		random = new Random();
	}
	
	@Override
	public SudokuLineGene createGene(int geneLength, List<FixedValue> fixedValues) {
		int[] dna = new int[geneLength];
		
		Collections.sort(fixedValues, new Comparator<FixedValue>() {
			@Override
			public int compare(FixedValue o1, FixedValue o2) {
				return o1.getIndex() - o2.getIndex();
			}
		});
		
		Set<Integer> possibleValues = new HashSet<Integer>(geneLength);
		for (int i = 0; i < geneLength; ++i)
			possibleValues.add(new Integer(i));
		
		Iterator<FixedValue> fixedValuesIt = fixedValues.listIterator();
		if (fixedValuesIt.hasNext()) {
			FixedValue value = fixedValuesIt.next();
			int previousIndex = value.getIndex();
			
			dna[value.getIndex()] = value.getValue();
			possibleValues.remove(new Integer(value.getValue()));
			
			while (fixedValuesIt.hasNext()) {
				value = fixedValuesIt.next();
				assert(previousIndex != value.getIndex());
				previousIndex = value.getIndex();
				
				dna[value.getIndex()] = value.getValue();
				possibleValues.remove(new Integer(value.getValue()));
			}
		}
		
		// TODO can probably clean this up and use a list the whole way through
		List<Integer> possibleValuesList = new ArrayList<Integer>();
		possibleValuesList.addAll(possibleValues);
		Collections.shuffle(possibleValuesList);
		List<Integer> nonFixedIndices = new ArrayList<Integer>(possibleValues.size());
		for (int i = 0; i < geneLength; ++i)
			if (dna[i] == 0) {
				dna[i] = possibleValuesList.remove(0);
				nonFixedIndices.add(new Integer(i));
			}
		
		return new SudokuLineGene(dna, nonFixedIndices);
	}

	
	@Override
	public void mutate(SudokuLineGene gene) {
		List<Integer> nonFixedIndexes = gene.getNonFixedIndices();
		
		if(nonFixedIndexes.size() > 1) {
			int index1 = nonFixedIndexes.get(random.nextInt(nonFixedIndexes.size())).intValue();
			int index2 = nonFixedIndexes.get(random.nextInt(nonFixedIndexes.size())).intValue();
			
			int temp = gene.getValueAt(index1);
			gene.setValueAt(index1, gene.getValueAt(index2));
			gene.setValueAt(index2, temp);
		}
	}
	
}
